home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / comm / ytsg3.zip / YTSGDOS.C < prev    next >
C/C++ Source or Header  |  1995-12-25  |  43KB  |  993 lines

  1. /************************************************************************
  2.  * ytsgdos.c - Convery Yarn files to SOUP offline reader format using grep
  3.  *          syntax to select messages.  DOS version.  Removed wildcard
  4.  *          handling because there were compiler differences which I did
  5.  *          not want to play with right now.  A better idea would be to
  6.  *          rebuild with WATCOM.
  7.  * Copyright (C) 1995, Richard Curry Consulting: trindflo@fishnet.net
  8.  * All Rights Reserved
  9.  *
  10.  * My software is generally available as free software under the terms
  11.  * of the GNU General Public License.
  12.  *
  13.  * Parts of this software were copied from source code made available as
  14.  * part of IBMs Developer's Connection.  IBM copyright information has
  15.  * been retained in this file.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program in a file name 'COPYING'; if not, write to the
  24.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  *
  26.  * SUMMARY:
  27.  *    This file contains the code to translate/copy Yarn news files into
  28.  *    soup offline reader format.  This initially is intended to allow
  29.  *    cleanup of a corrupted Yarn newsbase.
  30.  *
  31.  *    To build: See build.cmd: expects IBM CSET/2 compiler.
  32.  *
  33.  *    To use:  see below
  34.  *
  35.  * REVISION HISTORY:
  36.  *
  37.  *   Date          Version  By    Purpose of Revision
  38.  * --------------- ------- -----  ---------------------------------------
  39.  * Thu  95-04-06    1.00    RRC   Initial Draft
  40.  * Mon  95-12-25    3.00    RRC   Handle X-Newsgroups correctly
  41.  *
  42.  ************************************************************************/
  43.  
  44. /************************************************/                         
  45. /* Author: G.R. Blair                           */
  46. /*         BOBBLAIR @ AUSVM1                    */
  47. /*         bobblair@bobblair.austin.ibm.com     */
  48. /*                                              */
  49. /* The following code is property of            */
  50. /* International Business Machines Corporation. */
  51. /*                                              */
  52. /* Copyright International Business Machines    */
  53. /* Corporation, 1991.  All rights reserved.     */
  54. /************************************************/
  55. /* Identification String to be put at the top of each AIXLIKE utility */
  56. char zqrzqvjb[] = "AIXLIKE V3.0 by Bob Blair - Copyright (c) 1990, 1992, IBM";
  57.  
  58. /*-----------------------------------------------------------------------*/
  59. /* Modification History:                                                 */
  60. /*      Release 1       5/1/91                                           */
  61. /* @1 05.08.91 changed fmf_init to find all files, even hidden           */
  62. /* @2 10.19.91 upper casing a line of over 256 bytes caused Trap D       */
  63. /* @3 05.22.92 failed on eof condition (trap d) reported by B. Kwan      */
  64. /* @4 05.03.93 modified for IBM C/Set2 compiler                          */
  65. /*-----------------------------------------------------------------------*/
  66.  
  67. /* ytsg: searches a file for a pattern.
  68.  
  69.    Usage:
  70.           ytsg [-v][-o][-i] {Pattern | -e Pattern | -f StringFile} [YarnFile]
  71. */
  72.  
  73. /* The ytsg command searches the input file specified by the *YarnFile*
  74. parameter (standard input by default) for news/mail messages matching a
  75. pattern.  The ytsg command searches specifically for *Pattern*
  76. parameters that are fixed strings.  The ytsg command outputs the message
  77. containing the matched line to soup formatted files.  The pattern that
  78. you are matching must be in the first 50,000 bytes of the file.
  79. A real regular expression parser here might be nice, but for now it is
  80. not to be.
  81.  
  82. The exit values of this command are:
  83.   0   A match was found
  84.   1   No match was found
  85.   2   A syntax error was found or a file was inaccessible (even if matches were
  86.       found).
  87.  
  88. Flags:
  89.       -e Pattern    Specifies a pattern.  This works the same as a simple
  90.                     pattern, but is useful when a pattern begins with a -.
  91.  
  92.       -f StringFile Specifies a file that contains strings to be matched.
  93.                     (The file may specify up to 256 strings in this
  94.                     implementation).
  95.  
  96.       -i            Ignores the case of letters when making comparisons.
  97.  
  98.       -o            Outputs the HEX offset of each message.  First message is
  99.                     at offset 0.
  100.  
  101.       -v            Displays all lines except those that match the specified
  102.                     pattern.
  103. */
  104.  
  105. /* -------------------------------------------------------------------------- */
  106. /*  Maintenance history:                                                      */
  107. /*           Jan 15 1991: Fixed case-insensitive search                       */
  108. /*                                                                            */
  109. /*                                                                            */
  110. /*                                                                            */
  111. /*                                                                            */
  112. /*                                                                            */
  113. /* -------------------------------------------------------------------------- */
  114.  
  115. #include <stdlib.h>
  116. #include <stdio.h>
  117. #include <ctype.h>
  118. #include <string.h>
  119. #include <io.h>
  120. #include <fcntl.h>
  121. #include <sys/types.h>
  122. #include <sys/stat.h>
  123. #include <errno.h>
  124. #define  INCL_BASE
  125. #define  INCL_NOPM
  126. #include <os2.h>
  127. /* #include "fmf.h" */
  128.  
  129. // #define BUFSIZE    30000
  130. #define BUFSIZE    50000
  131. #define MAXPATTERNS  256
  132. #define MAXLINE 255
  133. #define MATCHFOUND     0
  134. #define NOMATCHFOUND   1
  135. #define SOMEERROR      2
  136. #define YES            1
  137. #define NO             0
  138. #define BAILOUT       -1
  139. #define INIT           0
  140. #define NEXT           1
  141. #define TAB           0x09
  142. #define CR            0x0d
  143. #define LF            0x0a
  144. #define STDIN          0
  145. #define NONPOLISH      0
  146. #define REVERSE        1
  147. #define BUFEND         (buf + BUFSIZE)
  148.  
  149. char *optstring = "e:f:iov";           /* valid option letters */
  150. char *stdinC = "STDIN";
  151. char *pattern[MAXPATTERNS] = {NULL};     /* up to MAXPATTERNS pattern ptrs */
  152.  
  153.                    /*----------------------------*/
  154.                    /* Options and their defaults */
  155.                    /*----------------------------*/
  156. char *filespec = NULL;          /* file(s) to be searched */
  157. char *StringFile = NULL;        /* name of file containing patterns */
  158. int  logic = NONPOLISH;         /* search for matching or non-matching files? */
  159. int  subtreesrch = NO;          /* search subtrees for matching files ? */
  160. int  casesensitive = YES;       /* respect case in comparing to pattern? */
  161. int  showhexoffset = NO;        /* show hex offset with matching message? */
  162. ULONG ulOffset;                  /* ftell for current message start */
  163.  
  164. char readbuf[BUFSIZE];                  /* Work buffer                        */
  165. #if 0
  166. char inp_buf[65536];                    /* vbuf for speeding stdio access     */
  167. char out_buf[65536];                    /* vbuf for speeding stdio access     */
  168. #else
  169. char out_buf[4096];                    /* vbuf for speeding stdio access     */
  170. #endif
  171.  
  172. char szNewsGps[4096];                   /* String of newsgroups for this msg  */
  173. char szCurrentGroup[1024];              /* Current group messages are sent to */
  174.  
  175. unsigned long ulMsgByteCount;           /* # of bytes in current message      */
  176. unsigned long ulBytesToCopy;            /* # of bytes still to be copied      */
  177. unsigned long ulBytesThisTime;          /* # of bytes to copy this iteration  */
  178. unsigned long ulActualRead;             /* # of bytes actually read           */
  179. unsigned long ulActualWrite;            /* # of bytes actually written        */
  180. int retval;                             /* Return value from setvbuf          */
  181. int fHaveGp;                            /* Flag implies there is a current gp */
  182. unsigned short usMsgNum = 0;            /* Filename: 0000001.MSG, 0000002...  */
  183.  
  184.         /* Define file access structures */
  185. FILE *inp_file;
  186. FILE *out_file;
  187. FILE *pfAreas, *pfNewscr;
  188.  
  189.         /* Define constant strings */
  190. char *szAreasID = "AREAS";
  191. char szNewsrcID[512];
  192.  
  193.  
  194.  
  195.                    /*----------------------------*/
  196.                    /*    Function Prototypes     */
  197.                    /*----------------------------*/
  198. int init(int argc, char *argv[]);   /* Initialize from command line data */
  199. int getpatterns(char *filename);    /* get patterns from string file */
  200. void do_a_file(char *filename);     /* Logic for converting file to stream */
  201. void do_STDIN(void);                /* Logic when input file is stdin      */
  202.                                     /* Logic for matching lines in one file */
  203. void do_the_stream(FILE *stream, char *filename);
  204. void tell_usage(void);              /* Explain program usage */
  205.                                     /* Parse command line */
  206. int  getopt(int argc, char *argv[], char *opstring);
  207.  
  208. extern int optind;                  /* data exported by getopt() */
  209. extern char *optarg;
  210.                                     /* put out errors in a standard format */
  211. void myerror(int rc, char *area, char *details);
  212. extern char *myerror_pgm_name;      /* data imported by myerror */
  213.  
  214. int rexpres(char *pBuf, ULONG cbBuff);  /* Look for strings in buffer         */
  215. int env_init(void);                 /* Grab required files, env. strings, etc */
  216. void errex(char *mess_ptr);         /* Output and error and exit              */
  217. int showmsg(void);                  /* Output a 'found' indicator             */
  218.                                     /* Get a copy of 'Newsgroup:' string      */
  219. int CopyNewsGroupToString( char *pDest, ULONG MaxSizeDest );
  220. int SetupMail( void );              /* Allow for 'mail' and newsgroups        */
  221. int SetupNewAREA( char *szNewGpName );  /* Sets up new '.MSG' file            */
  222. int SubscribedTo( char *szTarget ); /* Checks to see if newsgroup in newsrc   */
  223. int swal(unsigned char *adrs);      /* Swap 32 bits end-to-end                */
  224. int fgetrsp(FILE *pf, char *bufr, int max); /* Read a line, discard >max      */
  225. int strnlzap(char *sp);             /* Find newline and NULL terminate at NL  */
  226. int finish_input(FILE *pf);         /* Read file until newline                */
  227.  
  228.  
  229. int  rtrnstatus = NOMATCHFOUND;     /* value returned on exit from ytsg */
  230.  
  231. /*----------------------------------------------------------------------------*/
  232. /*  main                                                                      */
  233. /*                                                                            */
  234. /*  mainline logic:                                                           */
  235. /*      Perform initialization                                                */
  236. /*      For each filespec on the command line                                 */
  237. /*         Initialize a search for files that match the spec                  */
  238. /*         For every file that does match the spec                            */
  239. /*            Try to match the pattern                                        */
  240. /*         Close the search for matching files to prepare for the next one.   */
  241. /*                                                                            */
  242. /*  None of this holds true if no filespec was specified.  In that case we    */
  243. /*  take input from STDIN and try to match that.                              */
  244. /*----------------------------------------------------------------------------*/
  245. int main(int argc, char *argv[])
  246. {
  247.    int  i, filespecindx;
  248.  
  249.    myerror_pgm_name = "ytsg";
  250.    if ( env_init() == BAILOUT )         /* Locate necessary files, env. etc   */
  251.      return(SOMEERROR);
  252.    if ( (filespecindx = init(argc, argv)) == BAILOUT)
  253.      return(SOMEERROR);
  254.    else
  255.      if (filespecindx > 0)
  256.        {
  257.          for (i = filespecindx; i < argc; i++)
  258.            {
  259.             do_a_file(argv[i]);
  260.            }
  261.        }
  262.      else
  263.        do_STDIN();
  264.    return(rtrnstatus);
  265. }
  266.  
  267. /*----------------------------------------------------------------------------*/
  268. /*  env_init                                                                  */
  269. /*                                                                            */
  270. /*  Do initialization:                                                        */
  271. /*      Open files and check for environment strings which are necessary for  */
  272. /*      the operation of this program.                                        */
  273. /*                                                                            */
  274. /*----------------------------------------------------------------------------*/
  275. int env_init(void) {
  276.  
  277.   if ( getenv("HOME") == NULL )         /* Need HOME to find newsrc           */
  278.     errex("HOME environment variable must be set to find newsrc file.\n");
  279.  
  280.   strcpy(szNewsrcID, getenv("HOME"));   /* Copy HOME address into name base   */
  281.   strcat(szNewsrcID, "\\yarn\\newsrc.");  /* add filename string              */
  282.  
  283.   pfNewscr = fopen(szNewsrcID , "r");   /* Open list of subscribed newsgroups */
  284.   if (pfNewscr == NULL) {
  285.     printf("Attempting to open newsrc file at %s ", szNewsrcID);
  286.     perror("");
  287.     exit(3);
  288.   }
  289.  
  290.   if ( access(szAreasID,0) == 0 )       /* If this file exists                */
  291.     errex("AREAS file already exists. Terminating to avoid corruption.\n");
  292.  
  293.   pfAreas = fopen(szAreasID, "wb");     /* Open list of AREAS (part of SOUP)  */
  294.   if (pfAreas == NULL)
  295.     errex("Can't open AREAS file.\n");
  296.  
  297.  
  298.   fHaveGp = FALSE;                      /* Flag no current group              */
  299.   return YES;
  300. }
  301.  
  302. /*----------------------------------------------------------------------------*/
  303. /*  init                                                                      */
  304. /*                                                                            */
  305. /*  Do initialization:                                                        */
  306. /*      Examine command line options and set internal variables accordingly.  */
  307. /*      If a pattern wasn't specified with -f, take if from the next command  */
  308. /*       line position; complain if there isn't one.                          */
  309. /*      If there are remaining command line arguments, they are file specs.   */
  310. /*                                                                            */
  311. /*                                                                            */
  312. /*                                                                            */
  313. /*                                                                            */
  314. /*----------------------------------------------------------------------------*/
  315. int init(int argc, char *argv[])
  316. {
  317.     int rtrnindx = 0;
  318.     int args, i;
  319. #ifdef I16
  320.     char c;
  321. #else
  322.     int c;
  323. #endif
  324.     char *p;
  325.     int cu;
  326.  
  327.     for (i = 0; i < MAXPATTERNS; pattern[i++] = NULL); /* initialize patterns */
  328. #ifdef I16
  329.     while ( (c = (char)getopt(argc, argv, optstring)) != EOF)
  330. #else
  331.     while ( (c = getopt(argc, argv, optstring)) != EOF)
  332. #endif
  333.     {
  334.  
  335.         cu = toupper(c);
  336.         switch (cu)
  337.         {
  338.             case 'V':    logic = REVERSE;
  339.                break;
  340.             case 'I':    casesensitive = NO;
  341.                break;
  342.             case 'O':    showhexoffset = YES;
  343.                break;
  344.             case 'E':    if (StringFile == NULL)
  345.                            pattern[0] = optarg;
  346.                          else
  347.                            {
  348.                               tell_usage();
  349.                               return(BAILOUT);
  350.                            }
  351.                break;
  352.             case 'F':    if (pattern[0] == NULL)
  353.                            StringFile = optarg;
  354.                          else
  355.                            {
  356.                               tell_usage();
  357.                               return(BAILOUT);
  358.                            }
  359.                break;
  360.             default:     tell_usage();
  361.                          return(BAILOUT);
  362.                break;
  363.  
  364.         } /* endswitch */
  365.     }
  366.  
  367.     args = optind;
  368.     if ( (pattern[0] == NULL) && (StringFile == NULL) )
  369.       if  (args < argc)
  370.         pattern[0] = argv[args++];
  371.  
  372.     if (StringFile != NULL)
  373.       if (pattern[0] == NULL)
  374.         {
  375.           if (getpatterns(StringFile) == BAILOUT)
  376.             return(BAILOUT);
  377.         }
  378.       else
  379.         {
  380.           tell_usage();
  381.           return(BAILOUT);
  382.         }
  383.  
  384.     if ( (pattern[0] == NULL) && (StringFile == NULL) )
  385.       {
  386.         tell_usage();
  387.         return(BAILOUT);
  388.       }
  389.  
  390.     if (args < argc)
  391.       rtrnindx = args++;
  392.  
  393.     if (casesensitive == NO)  /* upper case the patterns if search is */
  394.       if (pattern != NULL)              /* insensitive */
  395.         for (i = 0; pattern[i]; i++)
  396.           for (p = pattern[i]; *p; p++)
  397.             *p = (char)toupper(*p);
  398.     return(rtrnindx);
  399. }
  400.  
  401. /*----------------------------------------------------------------------------*/
  402. /*  getpatterns                                                               */
  403. /*                                                                            */
  404. /*                                                                            */
  405. /*                                                                            */
  406. /*                                                                            */
  407. /*                                                                            */
  408. /*----------------------------------------------------------------------------*/
  409. int getpatterns(char *filename)
  410. {
  411.    FILE *stream;
  412.    char buff[MAXLINE], *p, *q;
  413.    int i;
  414.  
  415.    i = 0;
  416.    if ( (stream = fopen(filename, "r")) != NULL)           /* @4c */
  417.      {
  418.        while (fgets(buff, MAXLINE, stream) != NULL)
  419.          {
  420.            if (i >= MAXPATTERNS)
  421.              {
  422.                fprintf(stderr,
  423.                "Only the first %d patterns in the pattern file will be used\n",
  424.                MAXPATTERNS);
  425.                break;
  426.              }
  427.            if ( (pattern[i] = (char *)malloc(strlen(buff) + 1)) != NULL )
  428.              {
  429.                for (p = pattern[i], q = buff;
  430.                     *q && (*q != CR) && (*q != LF);
  431.                     *p++ = *q++);
  432.                *p = '\0';
  433.                i++;
  434.              }
  435.            else
  436.              {
  437.                myerror(ERROR_NOT_ENOUGH_MEMORY, "getting space for patterns", "");
  438.                return(BAILOUT);
  439.              }
  440.          }
  441.        fclose(stream);
  442.      }
  443.    else
  444.      {
  445.        printf("Could not open StringFile %s\n", filename);
  446.        return(BAILOUT);
  447.      }
  448.    return(YES);
  449. }
  450. /*----------------------------------------------------------------------------*/
  451. /*  do_a_file                                                                 */
  452. /*                                                                            */
  453. /*                                                                            */
  454. /*                                                                            */
  455. /*                                                                            */
  456. /*                                                                            */
  457. /*                                                                            */
  458. /*                                                                            */
  459. /*                                                                            */
  460. /*                                                                            */
  461. /*                                                                            */
  462. /*----------------------------------------------------------------------------*/
  463. void do_a_file(char *filename)
  464. {
  465.     FILE *stream;
  466.  
  467.     if ( (stream = fopen(filename, "rb"))  != NULL)
  468.         {
  469.           do_the_stream(stream, filename);
  470.           fclose(stream);
  471.         }
  472.       else
  473.         {
  474.           rtrnstatus = SOMEERROR;
  475. //          perror(filename);
  476.           myerror(0, "File open error", filename);
  477.         }
  478. }
  479.  
  480. /*----------------------------------------------------------------------------*/
  481. /*  do_STDIN                                                                  */
  482. /*                                                                            */
  483. /*  Same thing as do_a_file(), really, except that we already know the handle.*/
  484. /*                                                                            */
  485. /*----------------------------------------------------------------------------*/
  486. void do_STDIN()
  487. {
  488.    FILE *stream;
  489.  
  490.    if ( (stream = fdopen(STDIN, "rb"))  != NULL)
  491.       do_the_stream(stream, stdinC);
  492.    else
  493.       {
  494.         rtrnstatus = SOMEERROR;
  495. //        perror("stdin->stream");
  496.         myerror(0, "Opening STDIN as stream", "");
  497.       }
  498. }
  499.  
  500. /*----------------------------------------------------------------------------*/
  501. /*  do_the_stream                                                             */
  502. /*                                                                            */
  503. /*                                                                            */
  504. /*                                                                            */
  505. /*                                                                            */
  506. /*                                                                            */
  507. /*                                                                            */
  508. /*                                                                            */
  509. /*                                                                            */
  510. /*                                                                            */
  511. /*                                                                            */
  512. /*----------------------------------------------------------------------------*/
  513. void do_the_stream(FILE *inp_file, char *filename)
  514. {
  515.   printf("Extracting messages from file %s: ", filename);
  516.  
  517.   for (;;) {                            /* Until end of file                  */
  518.     if (feof(inp_file)) break;
  519.  
  520.         /* Read the byte count */
  521.     if ( fread(&ulMsgByteCount, 1, 4, inp_file) != 4 ) {
  522.       if (feof(inp_file)) break;
  523.       else {
  524.         perror("Error reading from input file");
  525.         exit(3);
  526.       }                                         
  527.     }
  528.  
  529.     if ( (ulMsgByteCount & 0xffff0000) != 0 ) { /* > 64K in one message       */
  530.       printf("Message length of %ld found\n", ulMsgByteCount);
  531.     }
  532.  
  533.     ulBytesToCopy = ulMsgByteCount;
  534.     ulBytesThisTime = min(ulBytesToCopy, sizeof(readbuf));
  535.  
  536.     ulOffset = ftell(inp_file);
  537.  
  538.         /* Read up to 64K of the message */
  539.     ulActualRead = fread(readbuf, 1, ulBytesThisTime, inp_file);
  540.     if ( ulActualRead != ulBytesThisTime ) {
  541.       if (feof(inp_file)) {
  542.         perror("Abnormal end of input file");
  543.         printf("Requested: %ld, Actual: %ld -- proceed [Y/n]? ",
  544.                                                 ulBytesThisTime, ulActualRead);
  545.         if ( tolower(getchar()) == 'n' ) exit(3);
  546.             /* Fill remainder with ^Z */
  547.         memset(readbuf+ulActualRead, 26, ulBytesThisTime-ulActualRead);
  548.       }
  549.       else {
  550.         perror("Error reading from input file");
  551.         exit(3);
  552.       }                                         
  553.     }
  554.  
  555.     if ( !rexpres(readbuf, ulActualRead) ) {  /* Look for a string match      */
  556.  
  557.         /* No match, clean up and move on to next message */
  558.       ulBytesToCopy -= ulBytesThisTime; /* Tally the bytes so far             */
  559.  
  560.       while ( ulBytesToCopy!=0 ) {      /* Complete the read of the message   */
  561.  
  562.           /* Read up to 64K of the message */
  563.         ulBytesThisTime = min(ulBytesToCopy, sizeof(readbuf));
  564.         ulActualRead = fread(readbuf, 1, ulBytesThisTime, inp_file);
  565.         if ( ulActualRead != ulBytesThisTime ) {
  566.           if (feof(inp_file)) {
  567.             perror("Abnormal end of input file in unselected message");
  568.             printf("Requested: %ld, Actual: %ld\n",
  569.                                                   ulBytesThisTime, ulActualRead);
  570.           }
  571.           else {
  572.             perror("Error reading from input file in unselected message");
  573.             exit(3);
  574.           }
  575.         }
  576.  
  577.         ulBytesToCopy -= ulBytesThisTime; /* Tally the successful read        */
  578.       } /* While more than 64K worth of message needs to be skipped */
  579.  
  580.       continue;                         /* Done.  Read next message           */
  581.     }
  582.  
  583.     showmsg();                          /* Indicate activity: message selected*/
  584.  
  585.     if ( !CopyNewsGroupToString(szNewsGps, sizeof(szNewsGps)) )
  586.       *szNewsGps = '\0';                /* Mail message then                  */
  587.  
  588.         /* If we have established a group, and hence a .MSG file */
  589.     if (fHaveGp) {
  590.  
  591.         /* If we are change in or out of mail mode */
  592.       if ( ((*szNewsGps & *szCurrentGroup) == 0) &&
  593.            ((*szNewsGps | *szCurrentGroup) != 0) ) {
  594.  
  595.         fclose(out_file);             /* New group, close current file      */
  596.         fHaveGp = FALSE;
  597.       }
  598.  
  599.         /* Check to see if the current message is part of this group */
  600.       else if ( strstr(szNewsGps, szCurrentGroup) == NULL )  {
  601.  
  602.         fclose(out_file);               /* New group, close current file      */
  603.         fHaveGp = FALSE;
  604.       }
  605.     }
  606.  
  607.         /* If we need to establish a group to put this message in */
  608.     if (!fHaveGp) {
  609.       char *szFirstGp, *szTestGp;
  610.  
  611.       if ( *szNewsGps == '\0' ) {       /* Switch into mail mode              */
  612.  
  613.         szTestGp = szNewsGps;           /* Point to NULL message              */
  614.         SetupMail();                    /* Handle SOUP protocol               */
  615.       }
  616.  
  617.       else {                            /* Normal mail group                  */
  618.  
  619.         /* Check each group in newsgroups list for a group we subscribe to */
  620.         szFirstGp = strtok(szNewsGps," ,");
  621.         for ( szTestGp=szFirstGp; szTestGp!=NULL; szTestGp=strtok(NULL," ,") )
  622.           if (SubscribedTo(szTestGp)) break;
  623.  
  624.         /* If there is no group we are subscribed to, go with the first one */
  625.         if ( szTestGp == NULL ) szTestGp = szFirstGp;
  626.  
  627.         SetupNewAREA(szTestGp);         /* Handle SOUP protocol               */
  628.       }
  629.  
  630.       strcpy(szCurrentGroup, szTestGp);
  631.       fHaveGp = TRUE;
  632.     }
  633.  
  634.         /* Identify the new message in SOUP format */
  635.     if ( *szCurrentGroup == '\0' ) {    /* If in mail mode, mail MSG format   */
  636.       unsigned long ulTemp;
  637.  
  638.       ulTemp = ulMsgByteCount;
  639.       swal((unsigned char *)&ulTemp);
  640.       fwrite(&ulTemp, 1, 4, out_file);
  641.     }
  642.     else                                /* Else in usenet mode                */
  643.       fprintf(out_file, "#! rnews %ld\n", ulMsgByteCount);
  644.  
  645.         /* Write whatever we previously read */
  646.     ulActualWrite = fwrite(readbuf, 1, ulBytesThisTime, out_file);
  647.     if ( ulActualWrite != ulBytesThisTime ) {
  648.       perror("Error writing to output file");
  649.       exit(3);
  650.     }
  651.     ulBytesToCopy -= ulBytesThisTime;   /* Tally the successful write         */
  652.  
  653.     while ( ulBytesToCopy!=0 ) {        /* Complete the copy of the message   */
  654.  
  655.         /* Read up to 64K of the message */
  656.       ulBytesThisTime = min(ulBytesToCopy, sizeof(readbuf));
  657.       ulActualRead = fread(readbuf, 1, ulBytesThisTime, inp_file);
  658.       if ( ulActualRead != ulBytesThisTime ) {
  659.         if (feof(inp_file)) {
  660.           perror("Abnormal end of input file");
  661.           printf("Requested: %ld, Actual: %ld -- Writing actual\n",
  662.                                                 ulBytesThisTime, ulActualRead);
  663.             /* Fill remainder with ^Z */
  664.           memset(readbuf+ulActualRead, 26, ulBytesThisTime-ulActualRead);
  665.         }
  666.         else {
  667.           perror("Error reading from input file");
  668.           exit(3);
  669.         }
  670.       }
  671.  
  672.         /* Write whatever we just read */
  673.       if (ulBytesThisTime != 0) {
  674.         ulActualWrite = fwrite(readbuf, 1, ulBytesThisTime, out_file);
  675.         if ( ulActualWrite != ulBytesThisTime ) {
  676.           perror("Error writing extended records to output file");
  677.           exit(3);
  678.         }
  679.       }
  680.       ulBytesToCopy -= ulBytesThisTime; /* Tally the successful write         */
  681.     } /* While more than 64K worth of message needs to be copies */
  682.   } /* For entire input file */
  683.  
  684. }
  685.  
  686. /*----------------------------------------------------------------------------*/
  687. /*  rexpres(Buffer, BytesInBuffer)                                            */
  688. /*    Search Buffer for any of the search strings.  Account for command       */
  689. /*    flags.  Return TRUE if found, FALSE if not.                             */
  690. /*                                                                            */
  691. /*----------------------------------------------------------------------------*/
  692. int rexpres(char *pBuf, ULONG cbBuff) {
  693.   int match = NO;                       /* Collect an answer                  */
  694.   char **pp;                            /* Array of pointers                  */
  695.  
  696.   if ( *pattern[0] == '*' ) match = YES;  /* Only wildcard in first version   */
  697.  
  698.   else for (pp=pattern; !match && *pp; pp++) {  /* For every pattern          */
  699.     char *residue = pBuf;               /* Sliding window through buffer      */
  700.     ULONG cbResidue = cbBuff;           /* # of bytes in the remaining tail   */
  701.     char *pFirstChar;                   /* Search pointer                     */
  702.  
  703.     if (casesensitive) {                /* Simple case...look for exact str   */
  704.  
  705.       while(cbResidue) {                /* While there are chars in the tail  */
  706.         ULONG cbSS;                     /* Bytes in search string             */
  707.  
  708.         pFirstChar = memchr(residue, **pp, cbResidue);
  709.         if (pFirstChar == NULL) break;  /* First char not found, no match     */
  710.  
  711.         cbResidue -= (pFirstChar - residue);  /* Get size of remaining buffer */
  712.         residue = pFirstChar;           /* Update pointer -- slide window     */
  713.  
  714.         cbSS = strlen(*pp);             /* Read total # chars in buffer       */
  715.         if ( cbSS > cbResidue) break;   /* Can not possibly match now         */
  716.  
  717.         if ( memcmp(*pp, residue, cbSS) == 0 ) {  /* If an exact match        */
  718.           match = YES;
  719.           break;
  720.         }
  721.  
  722.         cbResidue--; residue++;         /* Not the start of a match, try next */
  723.       } /* While searching the buffer */
  724.     } /* If case sensitive */
  725.  
  726.     else {                              /* Case insensitive -- complicated    */
  727.  
  728.       while(cbResidue) {                /* While there are chars in the tail  */
  729.         char *pBuffer, *pSrch;          /* Work pointers                      */
  730.         char *pLower, *pUpper;          /* Additional search pointers         */
  731.         int cbSrch;                     /* Bytes in search string             */
  732.  
  733.             /* Check for first character in either case */
  734.         pUpper = memchr(residue, **pp, cbResidue);
  735.         pLower = memchr(residue, tolower(**pp), cbResidue);
  736.  
  737.         pFirstChar = min(pLower, pUpper);   /* Go with lowest address         */
  738.         if (!pFirstChar)                /* If one of the addresses was NULL   */
  739.           pFirstChar = max(pLower, pUpper); /* Go with the other              */
  740.         if (!pFirstChar)                /* If both of the addresses are NULL  */
  741.           break;                        /* Nothing of interest left in buf    */
  742.  
  743.         cbResidue -= (pFirstChar - residue);  /* Get size of remaining buffer */
  744.         residue = pFirstChar;           /* Update pointer -- slide window     */
  745.  
  746.         match = YES;                    /* Now assume match was found         */
  747.         for (pBuffer=residue, pSrch=*pp, cbSrch=cbResidue;
  748.               *pSrch && cbSrch; pBuffer++, pSrch++, cbSrch-- )
  749.                                         /* And search a char at a time        */
  750.           if ( toupper(*pBuffer) != *pSrch)   /* For a mismatch               */
  751.             break;
  752.  
  753.         if ( *pSrch ) match = NO;       /* Search string was not exhausted    */
  754.  
  755.         if (match) break;
  756.  
  757.         cbResidue--; residue++;         /* Not the start of a match, try next */
  758.       } /* While searching the buffer */
  759.     } /* else case insensitive */
  760.   } /* else for every pattern until a match */
  761.  
  762.   if (logic == REVERSE) match = !match; /* handle reversing logic             */
  763.   return match;
  764. }
  765.  
  766.  
  767. /******************************************************************************/
  768. /* Major subroutines                                                          */
  769. /******************************************************************************/
  770.  
  771. /*----------------------------------------------------------------------------*/
  772. /*  SubscribedTo: Search the newsrc file in an attempt to locate szTarget     */
  773. /*  as a subscribed newsgroup.  Checks for (!) unsubscribed groups.           */
  774. /*----------------------------------------------------------------------------*/
  775. char szNewsrcLine[1024];
  776.  
  777. int SubscribedTo( char *szTarget ) {
  778.   char *pName;
  779.  
  780.   fseek(pfNewscr, 0, SEEK_SET);         /* Point to top of file               */
  781.  
  782.         /* While there is a line to get, read beginning of line */
  783.   while ( fgetrsp(pfNewscr, szNewsrcLine, sizeof(szNewsrcLine)-1) )
  784.   {
  785.     pName = strstr( szNewsrcLine, szTarget );
  786.     if ( pName == NULL ) continue;      /* Not this line, try another         */
  787.  
  788.     pName += strlen(szTarget);          /* Point just past the string         */
  789.     while ( (*pName == ' ') || (*pName == '\t') ) pName++;  /* Skip whitespace*/
  790.  
  791.     if (*pName == ':') return TRUE;     /* This is a group we subscribe to    */
  792.     if (*pName == '!') return FALSE;    /* This is a group we 'unsubscribed'  */
  793.       /* Or...it was something else! */
  794.   }
  795.  
  796.   return FALSE;                         /* Never found this group             */
  797. }
  798.  
  799. /*----------------------------------------------------------------------------*/
  800. /*  SetupNewAREA: Open a new MSG file, make entry in AREAS file, etc.         */
  801. /*----------------------------------------------------------------------------*/
  802. int SetupNewAREA( char *szNewGpName ) {
  803.   char szOutFileName[16];
  804.  
  805.         /* Log new MSG file to AREAS */
  806.   fprintf(pfAreas, "%07d\t%s\tun\n", ++usMsgNum, szNewGpName);
  807.  
  808.         /* Generate filename, open and setup output file */
  809.   sprintf(szOutFileName, "%07d.MSG", usMsgNum);
  810.  
  811.   out_file = fopen(szOutFileName, "wb");
  812.   if (out_file == NULL)
  813.     errex("Can't open new output file.\n");
  814.  
  815.   retval=setvbuf(out_file, out_buf, _IOFBF, sizeof(out_buf) );
  816.   if (retval!=0) errex("Unable to set output buffer\n");
  817.  
  818.   return TRUE;
  819. }
  820.  
  821. /*----------------------------------------------------------------------------*/
  822. /*  SetupMail: Open a new MSG file for mail, etc.                             */
  823. /*----------------------------------------------------------------------------*/
  824. int SetupMail( void ) {
  825.   char szOutFileName[16];
  826.  
  827.         /* Log new MSG file to AREAS */
  828.   fprintf(pfAreas, "%07d\tEmail\tbn\n", ++usMsgNum);
  829.  
  830.         /* Generate filename, open and setup output file */
  831.   sprintf(szOutFileName, "%07d.MSG", usMsgNum);
  832.  
  833.   out_file = fopen(szOutFileName, "wb");
  834.   if (out_file == NULL)
  835.     errex("Can't open new output file.\n");
  836.  
  837.   retval=setvbuf(out_file, out_buf, _IOFBF, sizeof(out_buf) );
  838.   if (retval!=0) errex("Unable to set output buffer\n");
  839.  
  840.   return TRUE;
  841. }
  842.  
  843.  
  844. /*----------------------------------------------------------------------------*/
  845. /*  CopyNewsGroupToString: Locate 'Newsgroups:' string and copy to a buffer.  */
  846. /*  must leave original to be copies to MSG file.                             */
  847. /*----------------------------------------------------------------------------*/
  848. char szNewsgpID[] = "Newsgroups:";
  849.  
  850. int CopyNewsGroupToString( char *pDest, ULONG MaxSizeDest ) {
  851.   char *pGps, *pGpsEnd, *pGpsFault;
  852.   unsigned long ulGpsLen;
  853.  
  854.   pGps = readbuf;                       /* Initialize search pointer          */
  855.   for (;;) {                            /* Search for correct or NULL string  */
  856.  
  857.     pGps = strstr( pGps, szNewsgpID );
  858.     if ( pGps == NULL ) return FALSE;   /* No list of groups found            */
  859.     if ( (pGps == readbuf) ||           /* If string starts at top            */
  860.          ( *(pGps-1) == '\n' ) ||       /* OR the beginning of a line         */
  861.          ( *(pGps-1) == ' ' ) )         /* OR is not part of a larger string  */
  862.       break;                            /* Then we have our string            */
  863.     pGps++;                             /* Otherwise, search again            */
  864.   }
  865.  
  866.       /* Check for end of header (Two \n's in a row) before newsgroup string */
  867.   pGpsFault = strstr( readbuf, "\n\n" );
  868.   if ( (pGpsFault!=NULL)  && (pGps > strstr(readbuf, "\n\n")) ) return FALSE;
  869.  
  870.   if ( (pGps != readbuf) &&             /* If string did not start at top     */
  871.        ( *(pGps-1) != '\n' ) ) {        /* AND did not start line             */
  872.     printf("Warning, 'Newsgroups:' identifier not at beginning of line\n");
  873.   }
  874.  
  875.   pGps += sizeof(szNewsgpID)-1;         /* Look past the Identifier           */
  876.  
  877.   pGpsEnd = strchr(pGps, '\n');         /* Find end of newsgroups line        */
  878.   if ( pGpsEnd == NULL ) return FALSE;  /* No end of line???                  */
  879.  
  880.   ulGpsLen = pGpsEnd-pGps;              /* Calculate the length of the line   */
  881.   ulGpsLen = min(ulGpsLen, MaxSizeDest-1);  /* Limit the size of the string   */
  882.  
  883.   memcpy(pDest, pGps, ulGpsLen);        /* Copy the string                    */
  884.   *(pDest+ulGpsLen) = '\0';             /* NULL terminate                     */
  885.  
  886.   return TRUE;
  887. }
  888.  
  889.  
  890. /******************************************************************************/
  891. /* Minor subroutines                                                          */
  892. /******************************************************************************/
  893.  
  894. /*----------------------------------------------------------------------------*/
  895. /*  fgetrsp: read a line.  Chars beyond 'max' are discarded.  Entire line is  */
  896. /*  guaranteed read.  Buffer is guaranteed NULL terminated.  Returns FALSE if */
  897. /*  no line is read (presumably end of file).                                 */
  898. /*----------------------------------------------------------------------------*/
  899. int fgetrsp(FILE *pf, char *bufr, int max) {
  900.  
  901.   if ( fgets(bufr, max, pf) == NULL )   /* Get a 'line'                       */
  902.     return FALSE;                       /* Normal termination mode            */
  903.  
  904.   if (!strnlzap(bufr))                  /* Attempt to kill terminating newline*/
  905.     finish_input(pf);                   /* Not found...complete reading line  */
  906.  
  907. return TRUE;
  908. }
  909.  
  910. /*----------------------------------------------------------------------------*/
  911. /*  strnlzap: Look for newline in a buffer replace it with NULL (zap it).     */
  912. /*  return TRUE if newline was found, FALSE if not.                           */
  913. /*----------------------------------------------------------------------------*/
  914. int strnlzap(char *sp) {
  915.  
  916.   while (*sp != '\n')                   /* Look for the newline               */
  917.     if (!(*sp++))                       /* If we hit end of string, rtn FALSE */
  918.       return FALSE;
  919.   *sp = 0;                              /* Kill string at newline */
  920.   return TRUE;                          /* Flag that we did our job */
  921. }
  922.  
  923. /*----------------------------------------------------------------------------*/
  924. /*  finish_input: read the file until newline or EOF is read.                 */
  925. /*----------------------------------------------------------------------------*/
  926. char zaparray[256];
  927. int finish_input(FILE *pf)
  928. {
  929.   for (;;) {
  930.     if ( fgets(zaparray, sizeof(zaparray), pf) == NULL ) return FALSE;
  931.     if ( strchr(zaparray, '\n') ) return TRUE;
  932.   }
  933. }
  934.  
  935. /*----------------------------------------------------------------------------*/
  936. /*  swal: Swap a long end to end (from big to little endian).                 */
  937. /*  call with the pointer to the long to be converted.                        */
  938. /*----------------------------------------------------------------------------*/
  939. int swal(unsigned char *adrs) {
  940.   unsigned char tempbyte;
  941.  
  942.   tempbyte  = *(adrs+3);
  943.   *(adrs+3) = *adrs;
  944.   *adrs++   = tempbyte;
  945.   tempbyte  = *(adrs+1);
  946.   *(adrs+1) = *adrs;
  947.   *adrs     = tempbyte;
  948.   return YES;
  949. }
  950.  
  951.  
  952.  
  953. /*----------------------------------------------------------------------------*/
  954. /*  errex: Prints an error message to the screen and does 'serious' error exit*/
  955. /*----------------------------------------------------------------------------*/
  956. void errex(char *mess_ptr) {
  957.   printf(mess_ptr);
  958.   exit(3);
  959. }
  960.  
  961. /*----------------------------------------------------------------------------*/
  962. /*  showmsg : Give user a warm fuzzy when we select a message.  If -o option  */
  963. /*    then print HEX offset of the message within source file.                */
  964. /*                                                                            */
  965. /*----------------------------------------------------------------------------*/
  966. int showmsg(void) {
  967.   if (showhexoffset)
  968.         printf("0x%lX-", ulOffset);
  969.   else  putchar('.');
  970.   return YES;
  971. }
  972.  
  973. /*----------------------------------------------------------------------------*/
  974. /*  tell_usage                                                                */
  975. /*                                                                            */
  976. /*----------------------------------------------------------------------------*/
  977. void tell_usage()
  978. {
  979.   printf("\n      Adapted from software provided by IBM, Copyright 1990, 1992\n");
  980.   printf("ytsg searches a Yarn newsbase for a pattern and makes SOUP.\n\n");
  981.   printf("Usage:\n");
  982.   printf("    ytsg [-vio] {Pattern | -e Pattern | -f StringFile} [YarnFile]\n");
  983.  
  984.   printf("\nFlags:\n");
  985.   printf("    -e Pattern    Specifies a pattern.\n");
  986.   printf("    -f StringFile Specifies a file that contains strings to be matched.\n");
  987.   printf("    -i            Ignores the case of letters when making comparisons.\n");
  988.   printf("    -o            Output the offset of each msg as found\n");
  989.   printf("    -v            Displays all lines except those that match pattern.\n");
  990.   printf("    -y            Ignore case of letters when making comparisons.\n");
  991. }
  992.  
  993.